/*
*  Copyright (u) 2006-2020, Chukie
*
*  SPDX-License-Identifier: Apache-2.0
*
*  @file     : uart_frame.u
*
*  @brief    :
*
*
*  Change Logs:
*  Date           Author          Notes
*  2020-09-19     zhaocj          the first version
*  2021-06-17     zhaocj          删除发送线程。由于应用层可能发送较大的数据，
*                                  发送线程的缓冲区可能无法存放较大的数据,
*                                 因此删除发送线程,应用层只接调用设备接口发送数据
*/
/* Includes -----------------------------------------------------------------*/
#include <uart_frame.h>
#include <rthw.h>
#include <string.h>

#ifdef SYSTEM_USING_SYSWATCHER
    #include <system.h>
#endif /*SYSTEM_USING_SYSWATCHER*/
#define DBG_TAG "[UART]"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
/* Private typedef ----------------------------------------------------------*/

/* Private define -----------------------------------------------------------*/
#ifndef SYSTEM_USING_SYSWATCHER
    #ifndef MIN
        #define MIN(a,b)            (((a) > (b)) ? (b) : (a))
    #endif /*MIN*/
    #ifndef MAX
        #define MAX(a,b)            (((a) > (b)) ? (a) : (b))
    #endif /*MAX*/

    #ifndef min
        #define min                 MIN
    #endif /*min*/

    #ifndef max
        #define max                 MAX
    #endif /*max*/

    /**
    * @brief sleep seconds
    *
    */
    #ifndef sleep
        #define sleep(s)    rt_thread_mdelay((s)*1000)
    #endif /*sleep*/
    /**
    * @brief sleep millseconds
    *
    */
    #ifndef sleepm
        #define sleepm(ms)  rt_thread_mdelay(ms)
    #endif /*sleepm*/
    /**
    * @brief get system now time in seconds
    * @Note: maybe wrapp
    * @return current system time in seconds
    */
    #ifndef uptime
        #define uptime()    ((rt_tick_get()) / RT_TICK_PER_SECOND)
    #endif /*uptime*/

    /**
    * @brief get system now time in millseconds
    * @Note: maybe wrapp
    * @return system now time in millseconds
    */
    #ifndef uptimem
        #define uptimem()   rt_tick_get_millisecond()
    #endif /*uptimem*/


    #ifndef time_after
        #define time_after(a,b)         ((long)(b) - (long)(a) < 0)
    #endif /*time_after*/

    #ifndef time_before
        #define time_before(a,b)        time_after(b,a)
    #endif /*time_before*/

    #ifndef time_after_eq
        #define time_after_eq(a,b)      ((long)(a) - (long)(b) >= 0)
        #define time_before_eq(a,b)     time_after_eq(b,a)
        #define time_in_range(a,b,c)    (time_after_eq(a,b) && time_before_eq(a,c))
    #endif /*time_after_eq*/
#endif /*SYSTEM_USING_SYSWATCHER*/

#if DBG_LVL == DBG_LOG && defined(LOG_HEX)
    #define LOG_DUMP(tag,mem,size)  LOG_HEX(tag,0,(rt_uint8_t*)(mem),size)
#else
    #define LOG_DUMP(tag,mem,size)
#endif
/* Private variables --------------------------------------------------------*/
static rt_slist_t uart_instance_list;
/* Extern variables ---------------------------------------------------------*/
/* Private function prototypes ----------------------------------------------*/
#define uart_instance_list_isempty()        rt_slist_isempty(&uart_instance_list)
#define uart_instance_list_foreach(node)    for ((node) = rt_slist_first(&uart_instance_list); (node); (node) = rt_slist_next(node))
#define uart_instance_list_append(u)        rt_slist_append(&uart_instance_list, &(u)->list)
#define uart_instance_list_remove(u)        rt_slist_remove(&uart_instance_list, &(u)->list)
#define uart_instance_list_entry(node)      rt_slist_entry(node, struct uart_instance, list)

/**
 * @brief device receive indicate callback
 *
 * @param device
 * @param size
 * @return rt_err_t
 */
static rt_err_t device_rx_ind(rt_device_t device, rt_size_t size)
{
    rt_slist_t *node;
    uart_instance_t instance;
    if (!device)
    {
        LOG_E("device is null!");
        return -RT_EINVAL;
    }

    if (uart_instance_list_isempty())
    {
        LOG_W("No available uart_frame instance!");
        return -RT_ENOSYS;
    }

    uart_instance_list_foreach(node)
    {
        instance = uart_instance_list_entry(node);
        if ((uintptr_t) instance->device == (uintptr_t) device)
        {
            rt_sem_release(&instance->rx_sem);
        }
    }
    return RT_EOK;
}

/**
 * @brief device send indicate callback
 *
 * @param device
 * @param size
 * @return rt_err_t
 */
static rt_err_t device_tx_ind(rt_device_t device,  void *buffer)
{
    rt_slist_t *node;
    uart_instance_t instance;
    if (!device)
    {
        LOG_E("device is null!");
        return -RT_EINVAL;
    }

    if (uart_instance_list_isempty())
    {
        LOG_W("No available pppd instance!");
        return -RT_ENOSYS;
    }

    uart_instance_list_foreach(node)
    {
        instance = uart_instance_list_entry(node);
        if ((uintptr_t) instance->device == (uintptr_t) device)
        {
            rt_sem_release(&instance->tx_sem);
        }
    }
    return RT_EOK;
}

static int device_read(uart_instance_t instance, char *buf, size_t size, size_t timeout_ms)
{
    rt_err_t rc = RT_EOK;
    int read = 0;
    ASSERT(instance);
    ASSERT(buf);

    while (read < size)
    {
#ifdef SYSTEM_USING_SYSWATCHER
        thread_ipc_recv(3);
#endif /*SYSTEM_USING_SYSWATCHER*/
        rc = rt_device_read(instance->device, 0, buf + read, size - read);
        if (rc > 0)
        {
            read += rc;
            rt_sem_control(&instance->rx_sem, RT_IPC_CMD_RESET, NULL);
            if (instance->input_hook)
            {
                read = instance->input_hook(instance, (uint8_t *)buf, read);
            }

        }
        else
        {
            rc = rt_sem_take(&instance->rx_sem, rt_tick_from_millisecond(timeout_ms));
            if (rc != RT_EOK)
            {
                break;
            }
        }
    }

    return read;
}

static int device_write(uart_instance_t instance, const char *data, size_t len, int timeout_ms)
{
    rt_size_t wrote = 0;
    ASSERT(instance);
    ASSERT(data);
    rt_int32_t timeout = timeout_ms >= 0 ? (rt_int32_t)rt_tick_from_millisecond(timeout_ms) : RT_WAITING_FOREVER;
    if (!instance->device || instance->device->ref_count < 1)
    {
        LOG_E("Device is unavailable!");
        return -RT_EIO;
    }
    
    if ((instance->device->open_flag & RT_DEVICE_FLAG_DMA_TX))
    {
        rt_sem_control(&instance->tx_sem, RT_IPC_CMD_RESET, RT_NULL);
        wrote = rt_device_write(instance->device, 0, data, len);
        if (rt_sem_take(&instance->tx_sem, timeout) != RT_EOK)
        {
            LOG_E("Write data timeout!");
            return -RT_EIO;
        }
    }
    else
    {
        wrote = rt_device_write(instance->device, 0, data, len);
    }

    return wrote;
}

static int device_open(uart_instance_t instance)
{
    rt_uint16_t open_flag = RT_DEVICE_FLAG_RDWR;
    rt_base_t level;

    while (instance->device->ref_count > 0)
    {
        LOG_W("The device %s may be in use,now close it!", instance->device->parent.name);
        rt_device_close(instance->device);
    }

    if ((instance->device->flag & RT_DEVICE_FLAG_DMA_TX))
    {
        open_flag |= RT_DEVICE_FLAG_DMA_TX;
        level = rt_hw_interrupt_disable();
        rt_device_set_tx_complete(instance->device, device_tx_ind);
        rt_hw_interrupt_enable(level);
    }
    else
    {
        if (instance->device->flag & RT_DEVICE_FLAG_INT_TX)
        {
            open_flag |= RT_DEVICE_FLAG_INT_TX;
        }
        level = rt_hw_interrupt_disable();
        rt_device_set_tx_complete(instance->device, NULL);
        rt_hw_interrupt_enable(level);
    }

    open_flag |= RT_DEVICE_FLAG_INT_RX;

    instance->config.serial_cfg.bufsz = RT_ALIGN_DOWN(instance->config.rx_cache_size, 4);

    level = rt_hw_interrupt_disable();
    rt_device_set_rx_indicate(instance->device, device_rx_ind);
    rt_hw_interrupt_enable(level);

    rt_device_control(instance->device, RT_DEVICE_CTRL_CONFIG, &instance->config.serial_cfg);
    if (RT_EOK != rt_device_open(instance->device, open_flag))
    {
        LOG_E("Can't open device %s", instance->device->parent.name);
        level = rt_hw_interrupt_disable();
        rt_device_set_rx_indicate(instance->device, NULL);
        rt_device_set_tx_complete(instance->device, NULL);
        rt_hw_interrupt_enable(level);
        return -RT_EIO;
    }
    LOG_I("Open %s with flag: 0x%X ok!", instance->device->parent.name, open_flag);

    return RT_EOK;
}

static int device_close(uart_instance_t instance)
{
    rt_base_t level;
    if (NULL != instance->device)
    {
        rt_device_close(instance->device);
        level = rt_hw_interrupt_disable();
        rt_device_set_rx_indicate(instance->device, NULL);
        rt_device_set_tx_complete(instance->device, NULL);
        rt_hw_interrupt_enable(level);
    }

    return RT_EOK;
}

static int uart_push_frame_to_rbb(uart_instance_t instance, uint8_t *data, size_t len)
{

    rt_rbb_blk_t block = NULL;
    const char *dev_name = instance->device->parent.name;

    LOG_D("Save %dB data to %s rx rbb", len, dev_name);
    block = rt_rbb_blk_alloc(instance->rbb, len);
    while (NULL == block)
    {
        LOG_W("%s rx rbb is full!", dev_name);
        block = rt_rbb_blk_get(instance->rbb);
        if (block)
        {
            LOG_W("Drop %dB data from %s rx rbb!", block->size, dev_name);
            instance->stat.rx_dropped += block->size;

            rt_rbb_blk_free(instance->rbb, block);
            block = rt_rbb_blk_alloc(instance->rbb, len);
            if (block)
            {
                break;
            }
        }
        else
        {
            break;
        }
    }

    if (NULL != block)
    {
        rt_memcpy(block->buf, data, len);
        rt_rbb_blk_put(block);
    }
    else
    {
        LOG_W("%s rx rbb is full,lost %dB data", dev_name, len);
        instance->stat.rx_dropped += len;
        return -RT_ENOMEM;
    }
    return len;
}

#ifdef SYSTEM_USING_SYSWATCHER

void uart_frame_ipc_handler(rt_uint32_t ev, void *msg, void *thread_param)
{
    uart_instance_t tmp;
    rt_thread_t self = rt_thread_self();
    if (ev & IPC_EVENT_SYS_KILL)
    {
        RT_ASSERT(thread_param);
        tmp = (uart_instance_t)thread_param;
        tmp->running = false;
        LOG_W("%s recv kill event, exit...", self->name);
    }

}

void uart_frame_cleanup(void *args)
{
    //do nothing
}
#endif /*SYSTEM_USING_SYSWATCHER*/

static void uart_rx_thread_entry(void *param)
{
    int read = 0;
    ASSERT(param);
    uart_instance_t instance = (uart_instance_t)param;
    instance->running = RT_TRUE;
    rt_sem_control(&instance->rx_sem, RT_IPC_CMD_RESET, NULL);
    rt_sem_control(&instance->tx_sem, RT_IPC_CMD_RESET, NULL);
    while (instance->running)
    {
#ifdef SYSTEM_USING_SYSWATCHER
        thread_ipc_recv(3);
#else /*!SYSTEM_USING_SYSWATCHER*/
        rt_thread_mdelay(3);
#endif /*SYSTEM_USING_SYSWATCHER*/
        read = device_read(instance, (char *)instance->rx_cache_buf, instance->config.rx_cache_size,
                           instance->config.interval_ms);
        if (read > 0)
        {
            size_t saved_len = 0;
            instance->stat.rx_bytes += read;
            while (read > saved_len)
            {
                int l = MIN(instance->config.max_frame_size, read - saved_len);
                uart_push_frame_to_rbb(instance, instance->rx_cache_buf + saved_len, l);
                saved_len += l;
            }
        }
    }
#ifdef SYSTEM_USING_SYSWATCHER
    tm_delete_self();
#else /*!SYSTEM_USING_SYSWATCHER*/
    LOG_I("exit.");
#endif /*SYSTEM_USING_SYSWATCHER*/
}

static int uart_frame_component_init(void)
{
    rt_slist_init(&uart_instance_list);
    LOG_I("UART frame component init ok!");
    return RT_EOK;
}
INIT_PREV_EXPORT(uart_frame_component_init);
#ifdef UART_FRAME_USING_STATISTICS
static void uart_frame_help(void)
{
    rt_kprintf("Usage: uart_frame <show|clear>\n");
    rt_kprintf("    cellular show(sh) : show uart frame statistics and info\n");
    rt_kprintf("    cellular clear(cl) <index>: Clear the uart frame statistics of the specified index\n");
    //rt_kprintf("    cellular reset(re) <index>: Reset the uart frame of the specified index\n\n");
}
static void uart_frame(uint8_t argc, char **argv)
{
    rt_slist_t *node;
    uart_instance_t instance;
    struct serial_configure *serial_cfg;
    uart_frame_statistics_t stat;
    int idx = 0;
    if (argc < 2)
    {
        uart_frame_help();
        return;
    }
    if (uart_instance_list_isempty())
    {
        rt_kprintf("No uart instance!\n");
        return ;
    }
    if (!strncmp(argv[1], "sh", 2))
    {
        uart_instance_list_foreach(node)
        {
            instance = uart_instance_list_entry(node);
            serial_cfg = &((struct rt_serial_device *)instance->device)->config;
            stat = &instance->stat;
            rt_kprintf("uart frame %d info: \n", idx + 1);
            rt_kprintf("    device name             : %s\n", instance->device->parent.name);
            rt_kprintf("    device configure        : %d %d %s %d %s bufsz=%d\n",
                       serial_cfg->baud_rate, serial_cfg->data_bits,
                       serial_cfg->parity == PARITY_EVEN ? "Even" : serial_cfg->parity == PARITY_ODD ? "Odd" : "None",
                       serial_cfg->stop_bits + 1,
                       serial_cfg->bit_order == BIT_ORDER_LSB ? "LSB" : "MSB",
                       serial_cfg->bufsz);
            rt_rbb_t rbb = instance->rbb;
            rt_kprintf("    Rx ring buffer size     : %d\n", rbb->buf_size);
            rt_kprintf("    Rx ring buffer block num: %d\n", rbb->blk_max_num);
            rt_kprintf("    Rx ring buffer frame num: %d\n", rt_slist_len(&rbb->blk_list));

            rt_kprintf("    Receive cache size      : %d\n", instance->config.rx_cache_size);
            rt_kprintf("    Max frame size          : %d\n", instance->config.max_frame_size);
            rt_kprintf("    Scan interval           : %d\n", instance->config.interval_ms);
            rt_kprintf("\nuart frame %d statistics: \n", idx + 1);
            rt_kprintf("    Total receive bytes     : %u\n", stat->rx_bytes);
            rt_kprintf("    Receive dropped bytes   : %u\n", stat->rx_dropped);
            rt_kprintf("    Total send bytes        : %u\n", stat->tx_bytes);
            rt_kprintf("    Send dropped bytes      : %u\n\n", stat->tx_dropped);
            idx ++;
        }
    }
    else if (!strncmp(argv[1], "cl", 2))
    {
        if (argc < 3)
        {
            uart_frame_help();;
            return ;
        }
        int index = atoi(argv[2]);
        if (0 == index)
        {
            rt_kprintf("Invalid uart frame index: %s\n", argv[2]);
            return;
        }
        index -= 1;
        idx = 0;
        uart_instance_list_foreach(node)
        {
            instance = uart_instance_list_entry(node);
            if (index == idx)
            {
                stat = &instance->stat;
                rt_kprintf("uart frame[%d] statistics is cleared!\n", idx + 1);
                stat->rx_bytes = 0;
                stat->tx_bytes = 0;
                stat->rx_dropped = 0;
                stat->tx_dropped = 0;
                break;
            }
            idx ++;
        }
    }
    else
    {
        uart_frame_help();
    }
}
MSH_CMD_EXPORT(uart_frame, show uart frame statistics);
#endif /*UART_FRAME_USING_STATISTICS*/
/* Public function prototypes -----------------------------------------------*/

/**
 * @brief Initialize a uart frame instance,and start it
 *
 * @param instance uart frame instance,reference to uart_instance_t
 * @param dev_name devcie name
 * @param config   uart frame instance,refernce to uart_frame_config_t
 * @param hook     user hook that will be call when receive data from device
 * @return int
 *              RT_EOK: success
 *              !RT_EOK: failed
 */
int uart_frame_init(uart_instance_t instance, const char *dev_name, uart_frame_config_t config,
                    uart_frame_input_hook hook)
{
    rt_slist_t *node;
    uart_instance_t tmp;
    int idx = 0;
    char name[RT_NAME_MAX] = {0};
    rt_device_t dev = NULL;
    ASSERT(instance);
    ASSERT(dev_name);
    ASSERT(config);

    dev = rt_device_find(dev_name);
    if (!dev)
    {
        LOG_E("Can't find device %s", dev_name);
        return -RT_EIO;
    }

    if (RT_Device_Class_Char != dev->type)
    {
        LOG_E("%s is not a char device!", dev_name);
        return -RT_EIO;
    }

    uart_instance_list_foreach(node)
    {
        tmp = uart_instance_list_entry(node);
        if ((uintptr_t)tmp == (uintptr_t)instance)
        {
            LOG_W("uart frame instance%d@%p has been initialized!", idx, instance);
            return RT_EOK;
        }
        if ((uintptr_t) tmp->device == (uintptr_t) dev)
        {
            LOG_E("%s has been used by uart_instance%d!", dev_name, idx);
            return -RT_EBUSY;
        }
        idx++;
    }
    rt_memset(instance, 0, sizeof(struct uart_instance));

    if (!config->max_frame_size)
    {
        LOG_W("invalid max_frame_size(%d), use default(%d)", config->max_frame_size, UART_FRAME_DEFAULT_RX_FRAME_SIZE);
        config->max_frame_size = UART_FRAME_DEFAULT_RX_FRAME_SIZE;
    }

    if (config->interval_ms < 1)
    {
        LOG_W("invalid interval_ms(%d), use default(%d)", config->interval_ms, UART_FRAME_DEFAULT_RX_FRAME_INTERVALE);
        config->interval_ms = UART_FRAME_DEFAULT_RX_FRAME_INTERVALE;
    }

    if (config->rx_cache_size < UART_FRAME_RX_CACHE_MIN_SIZE)
    {
        config->rx_cache_size = UART_FRAME_RX_CACHE_MIN_SIZE;
    }

    if (config->rx_block_num < UART_FRAME_RX_MIN_BLK_NUM)
    {
        config->rx_block_num = UART_FRAME_RX_MIN_BLK_NUM;
    }

    if (config->rx_buffer_size < UART_FRAME_RX_MIN_BUF_SIZE)
    {
        config->rx_buffer_size = UART_FRAME_RX_MIN_BUF_SIZE;
    }

    if (!config->serial_cfg.baud_rate)
    {
        LOG_W("Baudrate not set,use default(%d) ", BAUD_RATE_115200);
        config->serial_cfg.baud_rate = BAUD_RATE_115200;
    }
    if (!config->serial_cfg.data_bits)
    {
        LOG_W("Databits not set,use default(%d) ", DATA_BITS_8);
        config->serial_cfg.data_bits = DATA_BITS_8;
    }

    instance->device = dev;

    instance->config.rx_cache_size = config->rx_cache_size;
    instance->config.rx_block_num = config->rx_block_num;
    instance->config.rx_buffer_size = config->rx_buffer_size;

    instance->config.interval_ms = config->interval_ms;
    instance->config.max_frame_size = config->max_frame_size;
    instance->input_hook = hook;
    instance->config.serial_cfg = config->serial_cfg;

    if (RT_EOK != device_open(instance))
    {
        return -RT_ERROR;
    }

    instance->rx_cache_buf = malloc(instance->config.rx_cache_size);
    if (!instance->rx_cache_buf)
    {
        LOG_E("Can't malloc rx cache buf!");
        device_close(instance);
        return -RT_ENOMEM;
    }

    instance->rbb = rt_rbb_create(instance->config.rx_buffer_size, instance->config.rx_block_num);
    if (!instance->rbb)
    {
        LOG_E("Can't create rx rbb buf!");
        free(instance->rx_cache_buf);
        device_close(instance);
        return -RT_ENOMEM;
    }

    instance->stat.rx_bytes = 0;
    instance->stat.tx_bytes = 0;
    instance->stat.rx_dropped = 0;
    instance->stat.tx_dropped = 0;
    rt_snprintf(name, sizeof(name), "uf%dtx_lock", idx, dev->parent.name);
    rt_mutex_init(&instance->tx_lock, name, RT_IPC_FLAG_PRIO);
    rt_snprintf(name, sizeof(name), "uf%dtx_sem", idx, dev->parent.name);
    rt_sem_init(&instance->tx_sem, name, 0, RT_IPC_FLAG_PRIO);
    rt_snprintf(name, sizeof(name), "uf%drx_sem", idx, dev->parent.name);
    rt_sem_init(&instance->rx_sem, name, 0, RT_IPC_FLAG_PRIO);
    rt_snprintf(name, sizeof(name), "uf%d(%s)", idx, dev->parent.name);
    rt_thread_init(&instance->thread, name, uart_rx_thread_entry,
                   instance, instance->stack, UART_FRAME_THREAD_STACK_SIZE,
                   UART_FRAME_THREAD_PRIO, 64);

#ifdef SYSTEM_USING_SYSWATCHER
    tm_thread_add(&instance->thread, instance->thread.name, 20000,
                  uart_frame_cleanup, IPC_EVENT_SYS_KILL, uart_frame_ipc_handler);
#else /*SYSTEM_USING_SYSWATCHER*/
    rt_thread_startup(&instance->rx_handler.thread);
#endif /*SYSTEM_USING_SYSWATCHER*/
    LOG_D("uart frame%d init ok!", idx);
    uart_instance_list_append(instance);
    return RT_EOK;
}

/**
 * @brief create uart frame instance
 *
 * @param dev_name
 * @param config
 * @param hook
 * @return uart_instance_t
 */
uart_instance_t uart_frame_create(const char *dev_name, uart_frame_config_t config,
                                  uart_frame_input_hook hook)
{
    ASSERT(dev_name);
    ASSERT(config);
    uart_instance_t u = rt_malloc(sizeof(struct uart_instance));
    if (u)
    {
        if (RT_EOK == uart_frame_init(u, dev_name, config, hook))
        {
            return u;
        }
        rt_free(u);
        return RT_NULL;
    }
    return RT_NULL;
}

/**
 * @brief
 *
 * @param instance uart frame instance,reference to uart_instance_t
 * @param buf
 * @param buf_size
 * @return int
 */
int uart_frame_read(uart_instance_t instance, uint8_t *buf, size_t buf_size)
{
    rt_rbb_blk_t block = NULL;
    int ret = 0;
    if (!instance || !buf || !buf_size)
    {
        LOG_E("Invalid args!");
        return -RT_EINVAL;
    }
    if (!instance->running || !instance->device)
    {
        LOG_W("instance(@%p) is not ready!", instance);
        return 0;
    }

    block = rt_rbb_blk_get(instance->rbb);
    if (block)
    {
        LOG_D("Read %dB data from %s rx buffer!", block->size, instance->device->parent.name);
        ret = MIN(buf_size, block->size);
        rt_memcpy(buf, block->buf, ret);
        if (ret < block->size)
        {
            LOG_W("Read %dB data from %s rx buffer,left %dB", ret, instance->device->parent.name, block->size - ret);
            rt_memmove(block->buf, block->buf + ret, block->size - ret);
        }
        else
        {
            rt_rbb_blk_free(instance->rbb, block);
        }
        LOG_DUMP("SERIAL RX:", buf, ret);
    }
    return ret;
}

/**
 * @brief flush received data
 * 
 * @param instance 
 * @param buf 
 * @param buf_size 
 * @return int 
 */
int uart_frame_flush(uart_instance_t instance, uint8_t *buf, size_t buf_size)
{
    rt_rbb_blk_t block = NULL;
    if (!instance || !buf || !buf_size)
    {
        LOG_E("Invalid args!");
        return -RT_EINVAL;
    }

    rt_base_t level = rt_hw_interrupt_disable();
    while(NULL != (block = rt_rbb_blk_get(instance->rbb)))
    {
        LOG_D("Drop %dB %s recv data!", block->size, instance->device->parent.name);
        rt_rbb_blk_free(instance->rbb, block);
    }
    rt_hw_interrupt_enable(level);
    
    return RT_EOK;
}

/**
 * @brief write data to tx buffer
 *
 * @param instance uart frame instance,reference to uart_instance_t
 * @param data data to be sent
 * @param len   data length
 * @return int
 *          >0 : the data length saved in tx buffer
 *          <0: error
 */
int uart_frame_write(uart_instance_t instance, uint8_t *data, size_t len)
{
    int ret = RT_EOK;
    if (!instance || !data || !len)
    {
        LOG_E("Invalid args!");
        return -RT_EINVAL;
    }
    instance->stat.tx_bytes += len;
    if (!instance->running || !instance->device)
    {
        LOG_W("instance(@%p) is not ready!", instance);
        return 0;
    }
    LOG_D("Write %dB data to %s...", len, instance->device->parent.name);
    LOG_DUMP("SERIAL TX:",data, len);
    rt_mutex_take(&instance->tx_lock, RT_WAITING_FOREVER);
    ret = device_write(instance, (const char *)data, len, -1);
    if (ret < 0)
    {
        LOG_W("Write %dB data to %s failed!", len, instance->device->parent.name);
        instance->stat.tx_dropped += len;
    }
    rt_mutex_release(&instance->tx_lock);
    LOG_I("Write %dB data to %s success!", len, instance->device->parent.name);
    return ret;
}
/* End of file****************************************************************/

